package com.diagrammer.common
{
	import flash.display.Graphics;
	import flash.geom.Point;

	public class LinePainter
	{
//============================================================================
//parameters
//============================================================================
		private var graphics:Graphics;
		
		private var algorithm:Algorithm;
		
		private var _dashLine:Boolean = false;
		
		private var _dashLength:Number = 10;
		
		private var _dashGap:Number = 5;
		
		private var _lineColor:int = 0xdcdccc;
		
		private var _lineAlpha:Number = 1;
		
		private var _lineThickness:Number = 3;
		
		private var _arrowToShow:Boolean = true;
		
		private var _arrowToUpShow:Boolean = true;
		
		private var _arrowToDownShow:Boolean = true;
		
		private var _arrowToColor:int = -1;
		
		private var _arrowToAlpha:Number = -1;
		
		private var _arrowToThickness:Number = 2;
		
		private var _arrowToAngle:Number = Math.PI / 4;
		
		private var _arrowToLength:Number = 10;
		
		private var _arrowFromShow:Boolean = false;
		
		private var _arrowFromUpShow:Boolean = true;
		
		private var _arrowFromDownShow:Boolean = true;
		
		private var _arrowFromColor:int = -1;
		
		private var _arrowFromAlpha:Number = -1;
		
		private var _arrowFromThickness:Number = 2;
		
		private var _arrowFromAngle:Number = Math.PI / 4;
		
		private var _arrowFromLength:Number = 10;
//============================================================================
//constructor
//============================================================================
		public function LinePainter(graphics:Graphics)
		{
			algorithm = Algorithm.getInstance();
			this.graphics = graphics;
		}
//============================================================================
//public
//============================================================================
		/**
		 * 画直线+箭头
		 * @param fPoint 起始点
		 * @param tPoint 结束点
		 * 
		 */		
		public function drawLineArrow(fPoint:Point, tPoint:Point):void
		{
			if (!fPoint || !tPoint || !graphics || fPoint.equals(tPoint)) return;
			
			graphics.lineStyle(lineThickness, lineColor, lineAlpha);
			if (dashLine)
				drawDashLine(tPoint, fPoint);
			else
			{
				graphics.moveTo(fPoint.x, fPoint.y);
				graphics.lineTo(tPoint.x, tPoint.y);
			}
			var arrowUp:Point;
			var arrowDown:Point;
			if (arrowToShow)
			{
				graphics.lineStyle(arrowToThickness, arrowToColor, arrowToAlpha);
				if (arrowToUpShow)
				{
					arrowUp = algorithm.rotatePoint(fPoint, tPoint, arrowToAngle / 2);
					arrowUp = algorithm.getPointOnLine(tPoint, arrowUp, arrowToLength);
					graphics.moveTo(tPoint.x, tPoint.y);
					graphics.lineTo(arrowUp.x, arrowUp.y);
				}
				if (arrowToDownShow)
				{
					arrowDown = algorithm.rotatePoint(fPoint, tPoint, -arrowToAngle / 2);
					arrowDown = algorithm.getPointOnLine(tPoint, arrowDown, arrowToLength);
					graphics.moveTo(tPoint.x, tPoint.y);
					graphics.lineTo(arrowDown.x, arrowDown.y);
				}
			}
			if (arrowFromShow)
			{
				graphics.lineStyle(arrowFromThickness, arrowFromColor, arrowFromAlpha);
				if (arrowFromUpShow)
				{
					arrowUp = algorithm.rotatePoint(tPoint, fPoint, -arrowFromAngle / 2);
					arrowUp = algorithm.getPointOnLine(fPoint, arrowUp, arrowFromLength);
					graphics.moveTo(fPoint.x, fPoint.y);
					graphics.lineTo(arrowUp.x, arrowUp.y);
				}
				if (arrowFromDownShow)
				{
					arrowDown = algorithm.rotatePoint(tPoint, fPoint, arrowFromAngle / 2);
					arrowDown = algorithm.getPointOnLine(fPoint, arrowDown, arrowFromLength);
					graphics.moveTo(fPoint.x, fPoint.y);
					graphics.lineTo(arrowDown.x, arrowDown.y);
				}
			}
		}
		
		/**
		 * 画直线+分支
		 * @param fPoint 起始点
		 * @param tPoint 结束点
		 * 
		 */		
		public function drawLineBranch(fPoint:Point, tPoint:Point):void
		{
			if (!fPoint || !tPoint || !graphics || fPoint.equals(tPoint)) return;
			
			var arrowUp:Point;
			var arrowDown:Point;
			var tPoint2:Point = tPoint;
			var fPoint2:Point = fPoint;
			var arrowHLength:Number;
			if (arrowToShow)
			{
				graphics.lineStyle(arrowToThickness, arrowToColor, arrowToAlpha);
				arrowHLength = arrowToLength * Math.cos(arrowToAngle / 2);
				tPoint2 = algorithm.getPointOnLine(tPoint, fPoint, arrowHLength);
				graphics.moveTo(tPoint2.x, tPoint2.y);
				graphics.lineTo(tPoint.x, tPoint.y);
				if (arrowToUpShow)
				{
					arrowUp = algorithm.rotatePoint(tPoint, tPoint2, -arrowToAngle / 2);
					arrowUp = algorithm.getPointOnLine(tPoint2, arrowUp, arrowToLength);
					graphics.moveTo(tPoint2.x, tPoint2.y);
					graphics.lineTo(arrowUp.x, arrowUp.y);
				}
				if (arrowToDownShow)
				{
					arrowDown = algorithm.rotatePoint(tPoint, tPoint2, arrowToAngle / 2);
					arrowDown = algorithm.getPointOnLine(tPoint2, arrowDown, arrowToLength);
					graphics.moveTo(tPoint2.x, tPoint2.y);
					graphics.lineTo(arrowDown.x, arrowDown.y);
				}
			}
			if (arrowFromShow)
			{
				graphics.lineStyle(arrowFromThickness, arrowFromColor, arrowFromAlpha);
				arrowHLength = arrowFromLength * Math.cos(arrowFromAngle / 2);
				fPoint2 = algorithm.getPointOnLine(fPoint, tPoint, arrowHLength);
				graphics.moveTo(fPoint2.x, fPoint2.y);
				graphics.lineTo(fPoint.x, fPoint.y);
				if (arrowFromUpShow)
				{
					arrowUp = algorithm.rotatePoint(fPoint, fPoint2, arrowFromAngle / 2);
					arrowUp = algorithm.getPointOnLine(fPoint2, arrowUp, arrowFromLength);
					graphics.moveTo(fPoint2.x, fPoint2.y);
					graphics.lineTo(arrowUp.x, arrowUp.y);
				}
				if (arrowFromDownShow)
				{
					arrowDown = algorithm.rotatePoint(fPoint, fPoint2, -arrowFromAngle / 2);
					arrowDown = algorithm.getPointOnLine(fPoint2, arrowDown, arrowFromLength);
					graphics.moveTo(fPoint2.x, fPoint2.y);
					graphics.lineTo(arrowDown.x, arrowDown.y);
				}
			}
			graphics.lineStyle(lineThickness, lineColor, lineAlpha);
			if (dashLine)
				drawDashLine(fPoint2, tPoint2);
			else
			{
				graphics.moveTo(fPoint2.x, fPoint2.y);
				graphics.lineTo(tPoint2.x, tPoint2.y);
			}
		}
//============================================================================
//private
//============================================================================
		/**
		 * 画虚线
		 * @param fPoint
		 * @param tPoint
		 * @return 
		 * 
		 */		
		private function drawDashLine(fPoint:Point, tPoint:Point):void
		{
			var sPoint:Point = fPoint;
			var ePoint:Point;
			var lineLength:Number = Math.sqrt((tPoint.y - fPoint.y) * (tPoint.y - fPoint.y) + (tPoint.x - fPoint.x) * (tPoint.x - fPoint.x));
			if (lineLength == 0) return;
			var length:Number = 0;
			while (length < lineLength)
			{
				ePoint = algorithm.getPointOnLine(sPoint, tPoint, dashLength);
				length += dashLength + dashGap;
				if (length > lineLength) ePoint = tPoint;
				graphics.moveTo(sPoint.x, sPoint.y);
				graphics.lineTo(ePoint.x, ePoint.y);
				
				if (length < lineLength) sPoint = algorithm.getPointOnLine(ePoint, tPoint, dashGap);
			}
		}
//============================================================================
//getter/setter
//============================================================================

		/**
		 * 是否画虚线，默认为 false
		 */
		public function get dashLine():Boolean
		{
			return _dashLine;
		}

		/**
		 * @private
		 */
		public function set dashLine(value:Boolean):void
		{
			_dashLine = value;
		}

		/**
		 * 虚线单元长度[1,+)，默认为 10
		 */
		public function get dashLength():Number
		{
			return _dashLength;
		}

		/**
		 * @private
		 */
		public function set dashLength(value:Number):void
		{
			_dashLength = Math.max(value, 1);
		}

		/**
		 * 虚线单元间隔[1,+)，默认为 5
		 */
		public function get dashGap():Number
		{
			return _dashGap;
		}

		/**
		 * @private
		 */
		public function set dashGap(value:Number):void
		{
			_dashGap = Math.max(value, 1);
		}

		/**
		 * 线条颜色[0x000000,0xffffff]，默认为 0xdcdccc
		 */
		public function get lineColor():int
		{
			return _lineColor;
		}
		
		/**
		 * @private
		 */
		public function set lineColor(value:int):void
		{
			_lineColor = Math.min(Math.max(value, 0), 0xffffff);
		}
		
		/**
		 * 线条透明度[0,1]，默认为 1(不透明)
		 */
		public function get lineAlpha():Number
		{
			return _lineAlpha;
		}
		
		/**
		 * @private
		 */
		public function set lineAlpha(value:Number):void
		{
			_lineAlpha = Math.min(Math.max(value, 0), 1);
		}
		
		/**
		 * 线条粗细[0,255]，默认为 3
		 */
		public function get lineThickness():Number
		{
			return _lineThickness;
		}
		
		/**
		 * @private
		 */
		public function set lineThickness(value:Number):void
		{
			_lineThickness = Math.min(Math.max(value, 0), 255);
		}
		
		/**
		 * 是否需要显示结束点处箭头，默认为 true
		 */
		public function get arrowToShow():Boolean
		{
			return _arrowToShow;
		}
		
		/**
		 * @private
		 */
		public function set arrowToShow(value:Boolean):void
		{
			_arrowToShow = value;
		}
		
		/**
		 * 是否显示上方箭头（以起始点到结束点的方向为正方向，左边为Up），默认为 true &amp;&amp; arrowToShow
		 */
		public function get arrowToUpShow():Boolean
		{
			return _arrowToUpShow && arrowToShow;
		}

		/**
		 * @private
		 */
		public function set arrowToUpShow(value:Boolean):void
		{
			_arrowToUpShow = value;
		}

		/**
		 * 是否显示下方箭头（以起始点到结束点的方向为正方向，右边为Down），默认为 true &amp;&amp; arrowToShow
		 */
		public function get arrowToDownShow():Boolean
		{
			return _arrowToDownShow && arrowToShow;
		}

		/**
		 * @private
		 */
		public function set arrowToDownShow(value:Boolean):void
		{
			_arrowToDownShow = value;
		}
		
		/**
		 * 结束点箭头颜色[0x000000,0xffffff]，默认与 lineColor 相同
		 */
		public function get arrowToColor():int
		{
			return (_arrowToColor < 0 || _arrowToColor > 0xffffff)?lineColor:_arrowToColor;
		}
		
		/**
		 * @private
		 */
		public function set arrowToColor(value:int):void
		{
			_arrowToColor = value;
		}
		
		/**
		 * 结束点箭头透明度[0,1]，默认与 lineAlpha 相同
		 */
		public function get arrowToAlpha():Number
		{
			return (_arrowToAlpha < 0 || _arrowToAlpha > 1)?lineAlpha:_arrowToAlpha;
		}
		
		/**
		 * @private
		 */
		public function set arrowToAlpha(value:Number):void
		{
			_arrowToAlpha = value;
		}
		
		/**
		 * 结束点箭头粗细[0,255]，默认为 2
		 */
		public function get arrowToThickness():Number
		{
			return (_arrowToThickness < 0 || _arrowToThickness > 255)?lineThickness:_arrowToThickness;
		}
		
		/**
		 * @private
		 */
		public function set arrowToThickness(value:Number):void
		{
			_arrowToThickness = value;
		}
		
		/**
		 * 结束点箭头的内弧度[0, Math.PI]，默认为 PI/4
		 */
		public function get arrowToAngle():Number
		{
			return _arrowToAngle;
		}
		
		/**
		 * @private
		 */
		public function set arrowToAngle(value:Number):void
		{
			_arrowToAngle = value;
		}
		
		/**
		 * 结束点箭头边长度[0,+)，默认为 10
		 */
		public function get arrowToLength():Number
		{
			return _arrowToLength;
		}
		
		/**
		 * @private
		 */
		public function set arrowToLength(value:Number):void
		{
			_arrowToLength = Math.max(value, 0);
		}

		/**
		 * 是否需要显示起始点处箭头，默认为 false
		 */
		public function get arrowFromShow():Boolean
		{
			return _arrowFromShow;
		}

		/**
		 * @private
		 */
		public function set arrowFromShow(value:Boolean):void
		{
			_arrowFromShow = value;
		}

		/**
		 * 是否显示起始点上方箭头（以起始点到结束点的方向为正方向，左边为Up），默认为 true &amp;&amp; arrowFromShow
		 */
		public function get arrowFromUpShow():Boolean
		{
			return _arrowFromUpShow && arrowFromShow;
		}

		/**
		 * @private
		 */
		public function set arrowFromUpShow(value:Boolean):void
		{
			_arrowFromUpShow = value;
		}

		/**
		 * 是否显示起始点下方箭头（以起始点到结束点的方向为正方向，右边为Down），默认为 true &amp;&amp; arrowFromShow
		 */
		public function get arrowFromDownShow():Boolean
		{
			return _arrowFromDownShow && arrowFromShow;
		}

		/**
		 * @private
		 */
		public function set arrowFromDownShow(value:Boolean):void
		{
			_arrowFromDownShow = value;
		}

		/**
		 * 起始点箭头颜色[0x000000,0xffffff]，默认与 lineColor 相同
		 */
		public function get arrowFromColor():int
		{
			return (_arrowFromColor < 0 || _arrowFromColor > 0xffffff)?lineColor:_arrowFromColor;
		}

		/**
		 * @private
		 */
		public function set arrowFromColor(value:int):void
		{
			_arrowFromColor = value;
		}

		/**
		 * 起始点箭头透明度[0,1]，默认与 lineAlpha 相同
		 */
		public function get arrowFromAlpha():Number
		{
			return (_arrowFromAlpha < 0 || _arrowFromAlpha > 1)?lineAlpha:_arrowFromAlpha;
		}

		/**
		 * @private
		 */
		public function set arrowFromAlpha(value:Number):void
		{
			_arrowFromAlpha = value;
		}

		/**
		 * 起始点箭头粗细[0,255]，默认为 2
		 */
		public function get arrowFromThickness():Number
		{
			return (_arrowFromThickness < 0 || _arrowFromThickness > 255)?lineThickness:_arrowFromThickness;
		}

		/**
		 * @private
		 */
		public function set arrowFromThickness(value:Number):void
		{
			_arrowFromThickness = value;
		}

		/**
		 * 起始点箭头的内弧度[0, Math.PI]，默认为 PI/4
		 */
		public function get arrowFromAngle():Number
		{
			return _arrowFromAngle;
		}

		/**
		 * @private
		 */
		public function set arrowFromAngle(value:Number):void
		{
			_arrowFromAngle = value;
		}

		/**
		 * 起始点箭头边长度[0,+)，默认为 10
		 */
		public function get arrowFromLength():Number
		{
			return _arrowFromLength;
		}

		/**
		 * @private
		 */
		public function set arrowFromLength(value:Number):void
		{
			_arrowFromLength = Math.max(value, 0);
		}


	}
}